/*******************************************************************************
 * (c) Copyright 2008-2015 Microsemi Corporation.  All rights reserved.
 * 
 *  SmartFusion Microcontroller Subsystem GPIO bare metal software driver public
 *  API.
 *
 * SVN $Revision: 7837 $
 * SVN $Date: 2015-09-17 18:03:09 +0530 (Thu, 17 Sep 2015) $
 */

/*=========================================================================*//**
  @mainpage SmartFusion MSS GPIO Bare Metal Driver.

  @section intro_sec Introduction
  The SmartFusion Microcontroller Subsystem (MSS) includes a block of 32 general
  purpose input/outputs (GPIO).
  This software driver provides a set of functions for controlling the MSS GPIO
  block as part of a bare metal system where no operating system is available.
  This driver can be adapted for use as part of an operating system but the
  implementation of the adaptation layer between this driver and the operating
  system's driver model is outside the scope of this driver.
  
  @section hw_dependencies Hardware Flow Dependencies
  The configuration of all features of the MSS GPIOs is covered by this driver
  with the exception of the SmartFusion IOMUX configuration. SmartFusion allows
  multiple non-concurrent use of some external pins through IOMUX configuration.
  This feature allows optimizing external pin usage by assigning external pins
  for usage by either the microcontroller subsystem or the FPGA fabric.
  The MSS GPIO ports 0 to 15 are always connected to external pins but GPIO ports
  16 to 31 are routed through IOMUX to the SmartFusion device external pins.
  These IOMUX are configured using the MSS Configurator tool.
  Make sure the MSS GPIOs 16 to 31 are enabled in the MSS Configurator tool if
  you wish to use them
  
  @section theory_op Theory of Operation
  The MSS GPIO driver uses the SmartFusion "Cortex Microcontroler Software
  Interface Standard - Peripheral Access Layer" (CMSIS-PAL) to access MSS hardware
  registers. You must ensure that the SmartFusion CMSIS-PAL is either included
  in the software toolchain used to build your project or is included in your
  project. The most up-to-date SmartFusion CMSIS-PAL files can be obtained using
  the Actel Firmware Catalog.
  
  The MSS GPIO driver functions are grouped into the following categories:
    - Initiliazation
    - Configuration
    - Reading and setting GPIO state
    - Interrupt control
  
  The MSS GPIO driver is initialized through a call to the GPIO_init() function.
  The GPIO_init() function must be called before any other GPIO driver functions
  can be called.
  
  Each GPIO port is individually configured through a call to the
  MSS_GPIO_config() function. Configuration includes deciding if a GPIO port
  will be used as an input, an output or both. GPIO ports configured as inputs can be
  further configured to generate interrupts based on the input's state.
  Interrupts can be level or edge sensitive.
  
  The state of the GPIO ports can be read and set using the following functions:
    - MSS_GPIO_get_inputs()
    - MSS_GPIO_get_outputs()
    - MSS_GPIO_set_outputs()
    - MSS_GPIO_set_output()
    - MSS_GPIO_drive_inout()
    
  Interrupts generated by GPIO ports configured as inputs are controlled using
  the following functions:
    - MSS_GPIO_enable_irq()
    - MSS_GPIO_disable_irq()
    - MSS_GPIO_clear_irq()
  
 *//*=========================================================================*/
#ifndef MSS_GPIO_H_
#define MSS_GPIO_H_

#ifdef __cplusplus
extern "C" {
#endif 

#include "../../CMSIS/a2fxxxm3.h"

/*-------------------------------------------------------------------------*//**
  The mss_gpio_id_t enumeration is used to identify GPIOs as part of the
  parameter to functions:
    - MSS_GPIO_config(),
    - MSS_GPIO_drive_inout(),
    - MSS_GPIO_enable_irq(),
    - MSS_GPIO_disable_irq(),
    - MSS_GPIO_clear_irq()
 */
typedef enum __mss_gpio_id_t
{
    MSS_GPIO_0 = 0,
    MSS_GPIO_1 = 1,
    MSS_GPIO_2 = 2,
    MSS_GPIO_3 = 3,
    MSS_GPIO_4 = 4,
    MSS_GPIO_5 = 5,
    MSS_GPIO_6 = 6,
    MSS_GPIO_7 = 7,
    MSS_GPIO_8 = 8,
    MSS_GPIO_9 = 9,
    MSS_GPIO_10 = 10,
    MSS_GPIO_11 = 11,
    MSS_GPIO_12 = 12,
    MSS_GPIO_13 = 13,
    MSS_GPIO_14 = 14,
    MSS_GPIO_15 = 15,
    MSS_GPIO_16 = 16,
    MSS_GPIO_17 = 17,
    MSS_GPIO_18 = 18,
    MSS_GPIO_19 = 19,
    MSS_GPIO_20 = 20,
    MSS_GPIO_21 = 21,
    MSS_GPIO_22 = 22,
    MSS_GPIO_23 = 23,
    MSS_GPIO_24 = 24,
    MSS_GPIO_25 = 25,
    MSS_GPIO_26 = 26,
    MSS_GPIO_27 = 27,
    MSS_GPIO_28 = 28,
    MSS_GPIO_29 = 29,
    MSS_GPIO_30 = 30,
    MSS_GPIO_31 = 31
} mss_gpio_id_t;

/*-------------------------------------------------------------------------*//**
  GPIO ports definitions used to identify GPIOs as part of the parameter to
  function MSS_GPIO_set_outputs().
  These definitions can also be used to identity GPIO through logical
  operations on the return value of function MSS_GPIO_get_inputs().
 */
#define MSS_GPIO_0_MASK		    0x00000001UL
#define MSS_GPIO_1_MASK		    0x00000002UL
#define MSS_GPIO_2_MASK         0x00000004UL
#define MSS_GPIO_3_MASK	        0x00000008UL
#define MSS_GPIO_4_MASK	        0x00000010UL
#define MSS_GPIO_5_MASK	        0x00000020UL
#define MSS_GPIO_6_MASK	        0x00000040UL
#define MSS_GPIO_7_MASK	        0x00000080UL
#define MSS_GPIO_8_MASK	        0x00000100UL
#define MSS_GPIO_9_MASK		    0x00000200UL
#define MSS_GPIO_10_MASK		0x00000400UL
#define MSS_GPIO_11_MASK		0x00000800UL
#define MSS_GPIO_12_MASK		0x00001000UL
#define MSS_GPIO_13_MASK		0x00002000UL
#define MSS_GPIO_14_MASK		0x00004000UL
#define MSS_GPIO_15_MASK		0x00008000UL
#define MSS_GPIO_16_MASK		0x00010000UL
#define MSS_GPIO_17_MASK		0x00020000UL
#define MSS_GPIO_18_MASK		0x00040000UL
#define MSS_GPIO_19_MASK		0x00080000UL
#define MSS_GPIO_20_MASK		0x00100000UL
#define MSS_GPIO_21_MASK		0x00200000UL
#define MSS_GPIO_22_MASK		0x00400000UL
#define MSS_GPIO_23_MASK		0x00800000UL
#define MSS_GPIO_24_MASK		0x01000000UL
#define MSS_GPIO_25_MASK		0x02000000UL
#define MSS_GPIO_26_MASK		0x04000000UL
#define MSS_GPIO_27_MASK		0x08000000UL
#define MSS_GPIO_28_MASK		0x10000000UL
#define MSS_GPIO_29_MASK		0x20000000UL
#define MSS_GPIO_30_MASK		0x40000000UL
#define MSS_GPIO_31_MASK		0x80000000UL

/*-------------------------------------------------------------------------*//**
 * GPIO modes
 */
#define MSS_GPIO_INPUT_MODE              0x0000000002UL
#define MSS_GPIO_OUTPUT_MODE             0x0000000005UL
#define MSS_GPIO_INOUT_MODE              0x0000000003UL

/*-------------------------------------------------------------------------*//**
 * Possible GPIO inputs interrupt configurations.
 */
#define MSS_GPIO_IRQ_LEVEL_HIGH			0x0000000000UL
#define MSS_GPIO_IRQ_LEVEL_LOW			0x0000000020UL
#define MSS_GPIO_IRQ_EDGE_POSITIVE		0x0000000040UL
#define MSS_GPIO_IRQ_EDGE_NEGATIVE		0x0000000060UL
#define MSS_GPIO_IRQ_EDGE_BOTH			0x0000000080UL

/*-------------------------------------------------------------------------*//**
 * Possible states for GPIO configured as INOUT.
 */
typedef enum mss_gpio_inout_state
{
    MSS_GPIO_DRIVE_LOW = 0,
    MSS_GPIO_DRIVE_HIGH,
    MSS_GPIO_HIGH_Z
} mss_gpio_inout_state_t;

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_init() function initializes the SmartFusion MSS GPIO block. It
  resets the MSS GPIO hardware block and it also clears any pending MSS GPIO
  interrupts in the Cortex-M3 interrupt controller.
  
   @return
    none.
 */
void MSS_GPIO_init( void );

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_config() function is used to configure an individual
  GPIO port.
 
  @param port_id
    The port_id parameter identifies the GPIO port to be configured.
    An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example MSS_GPIO_0 identifies
    the first GPIO port and MSS_GPIO_31 the last one.
    
  @param config
    The config parameter specifies the configuration to be applied to the GPIO
    port identified by the port_id parameter. It is a logical OR of the required
    I/O mode and the required interrupt mode. The interrupt mode is not relevant
    if the GPIO is configured as an output only.
       These I/O mode constants are allowed:
           - MSS_GPIO_INPUT_MODE
           - MSS_GPIO_OUTPUT_MODE
           - MSS_GPIO_INOUT_MODE
       These interrupt mode constants are allowed:
           - MSS_GPIO_IRQ_LEVEL_HIGH
           - MSS_GPIO_IRQ_LEVEL_LOW
           - MSS_GPIO_IRQ_EDGE_POSITIVE
           - MSS_GPIO_IRQ_EDGE_NEGATIVE
           - MSS_GPIO_IRQ_EDGE_BOTH
  
   @return
    none.

  Example:
  The following call will configure GPIO 4 as an input generating interrupts on
  a low to high transition of the input:
  @code
  MSS_GPIO_config( MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE );
  @endcode
 */
void MSS_GPIO_config
(
    mss_gpio_id_t port_id,
    uint32_t config
);

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_set_outputs() function is used to set the state of all GPIO
  ports configured as outputs.
 
  @param value
    The value parameter specifies the state of the GPIO ports configured as
    outputs. It is a bit mask of the form (MSS_GPIO_n_MASK | MSS_GPIO_m_MASK) where n
    and m are numbers identifying GPIOs.
    For example (MSS_GPIO_0_MASK | MSS_GPIO_1_MASK | MSS_GPIO_2_MASK ) specifies
    that the first, second and third GPIOs' must be set high and all other
    outputs set low.
    The driver provides 32 mask constants, MSS_GPIO_0_MASK to MSS_GPIO_31_MASK
    inclusive, for this purpose.
  
  @return
    none.

  Example 1:
    Set GPIOs outputs 0 and 8 high and all other GPIO outputs low.
    @code
        MSS_GPIO_set_outputs( MSS_GPIO_0_MASK | MSS_GPIO_8_MASK );
    @endcode

  Example 2:
    Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs.
    @code
        uint32_t gpio_outputs;
        gpio_outputs = MSS_GPIO_get_outputs();
        gpio_outputs &= ~( MSS_GPIO_2_MASK | MSS_GPIO_4_MASK );
        MSS_GPIO_set_outputs(  gpio_outputs );
    @endcode

  @see MSS_GPIO_get_outputs()
 */
static __INLINE void
MSS_GPIO_set_outputs
(
   uint32_t value
)
{
    GPIO->GPIO_OUT = value;
}

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_set_output() function is used to set the state of a single GPIO
  port configured as output.
 
  @param port_id
    The port_id parameter identifies the GPIO port that is to have its output set.
    An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
    first GPIO port and MSS_GPIO_31 the last one.
  
  @param value
    The value parameter specifies the desired state for the GPIO output. A value
    of 0 will set the output low and a value of 1 will set the output high.
  
  @return
    none.
 */
void MSS_GPIO_set_output
(
    mss_gpio_id_t       port_id,
    uint8_t             value
);

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_get_inputs() function is used to read the current state of all
  GPIO ports confgured as inputs.
 
  @return
    This function returns a 32 bit unsigned integer where each bit represents
    the state of a GPIO input. The least significant bit represents the state of
    GPIO input 0 and the most significant bit the state of GPIO input 31.

  Example:
    Read and assign the current state of the GPIO outputs to a variable.
    @code
        uint32_t gpio_inputs;
        gpio_inputs = MSS_GPIO_get_inputs();
    @endcode
 */
static __INLINE uint32_t
MSS_GPIO_get_inputs( void )
{
    return GPIO->GPIO_IN;
}

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_get_outputs() function is used to read the current state of all
  GPIO ports confgured as outputs.
 
  @return
     This function returns a 32 bit unsigned integer where each bit represents
     the state of a GPIO output. The least significant bit represents the state
     of GPIO output 0 and the most significant bit the state of GPIO output 31.

  Example:
    Read and assign the current state of the GPIO outputs to a variable.
    @code
        uint32_t gpio_outputs;
        gpio_outputs = MSS_GPIO_get_outputs();
    @endcode
 */
static __INLINE uint32_t
MSS_GPIO_get_outputs( void )
{
    return GPIO->GPIO_OUT;
}

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_drive_inout() function is used to set the output state of a single
  GPIO port configured as an INOUT. An INOUT GPIO can be in one of three states:
    - high
    - low
    - high impedance
  An INOUT output would typically be used where several devices can drive the
  state of a shared signal line. The high and low states are equivalent to the
  high and low states of a GPIO configured as output. The high impedance state
  is used to prevent the GPIO from driving its output state onto the signal line,
  while at the same time allowing the input state of the GPIO to be read
 
  @param port_id
    The port_id parameter identifies the GPIO port for which you want to change
    the output state.
    An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example MSS_GPIO_0 identifies
    the first GPIO port and MSS_GPIO_31 the last one.
    
  @param inout_state
    The inout_state parameter specifies the state of the GPIO port identified by
    the port_id parameter. Allowed values of type mss_gpio_inout_state_t are:
                           - MSS_GPIO_DRIVE_HIGH
                           - MSS_GPIO_DRIVE_LOW
                           - MSS_GPIO_HIGH_Z (high impedance)

  @return
    none.

  Example:
    The call to MSS_GPIO_drive_inout() below will set the GPIO 7 output to the
    high impedance state.
    @code
    MSS_GPIO_drive_inout( MSS_GPIO_7, MSS_GPIO_HIGH_Z );
    @endcode
 */
void MSS_GPIO_drive_inout
(
    mss_gpio_id_t           port_id,
    mss_gpio_inout_state_t  inout_state
);

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_enable_irq() function is used to enable interrupt generation
  for the specified GPIO input. Interrupts are generated based on the state of
  the GPIO input and the interrupt mode configured for it by MSS_GPIO_config().
 
  @param port_id
    The port_id parameter identifies the GPIO port for which you want to enable
    interrupt generation.
    An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
    first GPIO port and MSS_GPIO_31 the last one.
    
  @return
    none.

  Example:
    The call to MSS_GPIO_enable_irq() below will allow GPIO 8 to generate
    interrupts.
    @code
    MSS_GPIO_enable_irq( MSS_GPIO_8 );
    @endcode
 */
void MSS_GPIO_enable_irq
(
    mss_gpio_id_t port_id
);

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_disable_irq() function is used to disable interrupt generation
  for the specified GPIO input.
 
  @param port_id
    The port_id parameter identifies the GPIO port for which you want to disable
    interrupt generation.
    An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
    first GPIO port and MSS_GPIO_31 the last one.
 
  @return
    none.

  Example:
    The call to MSS_GPIO_disable_irq() below will prevent GPIO 8 from generating
    interrupts.
    @code
    MSS_GPIO_disable_irq( MSS_GPIO_8 );
    @endcode
 */
void MSS_GPIO_disable_irq
(
    mss_gpio_id_t port_id
);

/*-------------------------------------------------------------------------*//**
  The MSS_GPIO_clear_irq() function is used to clear a pending interrupt from
  the specified GPIO input.
  Note: The MSS_GPIO_clear_irq() function must be called as part of any GPIO
  interrupt service routine (ISR) in order to prevent the same interrupt event
  retriggering a call to the GPIO ISR. The function also clears the interrupt
  in the Cortex-M3 interrupt controller through a call to NVIC_ClearPendingIRQ().
 
  @param port_id
    The port_id parameter identifies the GPIO input for which you want to clear the
    interrupt.
    An enumeration item of the form MSS_GPIO_n where n is the number of the GPIO
    port is used to identify the GPIO port. For example MSS_GPIO_0 identifies the
    first GPIO port and MSS_GPIO_31 the last one.
    
  @return
    none.

  Example:
    The example below demonstrates the use of the MSS_GPIO_clear_irq() function
    as part of the GPIO 9 interrupt service routine.  
    @code
    void GPIO9_IRQHandler( void )
    {
        do_interrupt_processing();
        
        MSS_GPIO_clear_irq( MSS_GPIO_9 );
    }
    @endcode
 */
void MSS_GPIO_clear_irq
(
    mss_gpio_id_t port_id
);

#ifdef __cplusplus
}
#endif

#endif /* MSS_GPIO_H_ */
